package wangn.procedure;

import wangn.adt.CFG;
import wangn.adt.lrparsing.LeafNode;
import wangn.adt.lrparsing.RootNode;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * LR分析算法，
 * 记录规约即可
 */
public class Matching {

    private RootNode lrParsingTable;
    private int inputPointer;
    private Stack<String> stack = new Stack<>();

    private List<String> log = new ArrayList<>();

    /**
     *
     * @param lrParsingTableRoot LR(1)表项的根节点
     * @param matchText 待匹配的字符串
     * @return void 将分析的结果（规约顺序）或者错误输出到文件中
     *
     */
    public void match(CFG cfg, RootNode lrParsingTableRoot, String matchText){
        this.lrParsingTable = lrParsingTableRoot;
        this.inputPointer =0;
        stack.add("0");//初始状态是0
        matchText += "$";//输入缓冲区末尾
        boolean hasError = false;
        while (!stack.isEmpty()){
            int s = Integer.parseInt(stack.peek());
            char a = matchText.charAt(inputPointer);
            LeafNode leafNode = lrParsingTable.getChild(s).getChild(a);
            if (leafNode==null){
                hasError = true;
                log.add("[ERROR]GRAMMAR NOT MATCHING, at: "+matchText.charAt(inputPointer));
                Character[] childs = lrParsingTable.getChild(s).getChildren();
                if (childs.length==0){
                    stack.pop();
                    continue;
                }
                else
                    leafNode = lrParsingTable.getChild(s).getChild(childs[0]);//随便选一个让分析器继续进行的符号
            }
            if (leafNode.isTransfer()){
                stack.push(a+"");
                stack.push(leafNode.getState()+"");
                inputPointer++;
            }else if(!leafNode.isTransfer()){
                if (leafNode.getState()==0){
                    if (hasError){
                        log.add("REFUSE");
                    }else
                        log.add("ACCEPT");
                    break;
                }else{
                    String leftGrammar = cfg.getGrammar(leafNode.getState()).getFirst();
                    String rightGrammar = cfg.getGrammar(leafNode.getState()).getSecond();
                    int popLength = rightGrammar.length()*2;
                    while (popLength-->0){
                        stack.pop();
                    }
                    s = Integer.parseInt(stack.peek());//当前栈顶状态
                    stack.push(leftGrammar);
                    stack.push(lrParsingTable.getChild(s).getChild(leftGrammar.charAt(0)).getState()+"");
                    log.add(leftGrammar+"->"+rightGrammar);
                }
            }else{
                log.add("[ERROR]CAN NOT RESUME FROM THIS TEXT");
            }
        }
        writeLog();
    }

    private void writeLog(){
        String path = getClass().getResource("../").getPath()+File.separator+"analyze.txt";
        File file = new File(path);

        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try(BufferedWriter bw = new BufferedWriter(new FileWriter(file))){
            int length = log.size();
            int i = 0;
            while (i < length){
                String record = log.get(i);
                bw.write(record);
                bw.newLine();
                i++;
            }
            bw.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
